#include "GameElementTool.h"

GameElementTool::GameElementTool():
    rend(RenderManager::getInstance()),
    gameEng(GameEngine::getInstance())
{
    currentElement=0;
    switchMode=false;
}

GameElementTool* GameElementTool::getInstance(){
    static GameElementTool* inst =0;
    if(!inst)return inst = new GameElementTool();
    else return inst;
}

GameElement* GameElementTool::getElementFromMouseCoords(int x, int y)
{
    vector3<float> temp = rend->mouseUtils.get3DFrom2D(x,y);
    temp += (temp-rend->Camera.getEyeVector()) * PT_OFFSET;
    vector3<int> pt = temp.cast<int>();
    GameElement* e=0;

    for(int i=MAX_GAME_ELEMENT_HEIGHT;i>0;i--,pt.y--)
    {
        //printf("%d %d %d\n",pt.x,pt.y,pt.z);
        if((e = gameEng->factory.getGeneric(pt)))break;
    }
    return e;
}

void GameElementTool::selectElementFromCoords(int x, int y){
    if(GameElement* e=getElementFromMouseCoords(x,y)){
        currentElement=e;
        gameCtx->updateGUIElement(getCurrentType());
        printf("ELEMENT SELECTED:%s\n",e->getName());
    }
}

void GameElementTool::addElementFromCoords(int x, int y){
    vector3<int> pt = rend->mouseUtils.getMouseOverVoxelPt(x,y);

    switch(gameCtx->getGUICurrentElement())
    {
        case DOOR:
            if(rend->isVoxelValid(pt.x,pt.y+1,pt.z)
               && !rend->isVoxelDrawn(pt.x,pt.y+1,pt.z))
            {
                pt.y++;
                gameEng->factory.addDoor(pt);
                gameEng->factory.getDoor(pt)->setFaceSide(gameCtx->getDoorFaceSide());
            }
            break;
        case ENEMY:
            if(rend->isVoxelValid(pt.x,pt.y+1,pt.z)
               && !rend->isVoxelDrawn(pt.x,pt.y+1,pt.z))
            {
                pt.y++;
                gameEng->factory.addEnemy(pt);
            }
            break;
        case SWITCH:
            if(rend->isVoxelValid(pt.x,pt.y+1,pt.z)
               && !rend->isVoxelDrawn(pt.x,pt.y+1,pt.z))
            {
                pt.y++;
                gameEng->factory.addSwitch(pt);
            }
            break;
        case SPIKES:
            if(rend->isVoxelValid(pt.x,pt.y+1,pt.z)
               && !rend->isVoxelDrawn(pt.x,pt.y+1,pt.z))
            {
                pt.y++;
                gameEng->factory.addSpikes(pt);
            }
            break;
        case LADDER:
            if(rend->isVoxelValid(pt.x,pt.y,pt.z))
            {
                gameEng->factory.addLadder(pt);
                gameEng->factory.getLadder(pt)->setOrientation((ORIENTATION)gameCtx->getLadderOrientation());
            }
            break;

        default:
        break;
    }

}

void GameElementTool::removeElementFromCoords(int x, int y)
{
    if(GameElement* e=getElementFromMouseCoords(x,y)){
        if(e==currentElement){
           currentElement=0;
        }

        MAP_TYPE& coll = gameEng->factory.getCollection();

        for(MAP_TYPE::iterator it=coll.begin();it!=coll.end();it++)
        {
            if(it->second->getType()==SWITCH)
            {
                dynamic_cast<ElementSwitch*>(it->second)->removeTarget(e);
            }
        }

        gameEng->factory.removeElement(e->s.position.cast<int>());
        gameCtx->updateGUIElement(getCurrentType());
    }
}

Result GameElementTool::mousePressEvent(QMouseEvent *event){
    if(event->button()==Qt::LeftButton)
    {
        if(getCurrentType()==SWITCH && event->modifiers()&Qt::AltModifier)
        {
          if(GameElement* e=getElementFromMouseCoords(event->x(),event->y()))
          {
              ElementSwitch* s = dynamic_cast<ElementSwitch*>(currentElement);
              s->addTarget(e);
              gameCtx->updateSwitchTargetList(s);
          }
        }
        else if(event->modifiers()&Qt::ShiftModifier)
        {
        //select
        selectElementFromCoords(event->x(),event->y());
        }
        else if(event->modifiers()&Qt::ControlModifier)
        {
            removeElementFromCoords(event->x(),event->y());
        }
        else
        {
        //add
        addElementFromCoords(event->x(), event->y());
        }

    }

    return Result(true);
}


Result GameElementTool::mouseMoveEvent(QMouseEvent *event){
    if(event->modifiers()&Qt::AltModifier && getCurrentType()==SWITCH)
    {
        if(GameElement* e=getElementFromMouseCoords(event->x(),event->y()))
        {
            switchCursorPos=e->geometry.center;
            //printf("%.2f,%.2f,%.2f",switchCursorPos.x,switchCursorPos.y,switchCursorPos.z);
        }
        else switchCursorPos=rend->mouseUtils.get3DFrom2D(event->x(),event->y());
        //printf("%.2f,%.2f,%.2f",switchCursorPos.x,switchCursorPos.y,switchCursorPos.z);
    }
    else
    {
        elementCursorPos=rend->mouseUtils.getMouseOverVoxelPt(event->x(),event->y());
    }
    return Result(true);
}

Result GameElementTool::keyPressEvent(QKeyEvent *event)
{
    if(event->modifiers()&Qt::AltModifier)switchMode=true;
    else switchMode=false;
    return Result(true);
}

Result GameElementTool::keyReleaseEvent(QKeyEvent *event)
{
    switchMode=false;
    return Result(true);
}

void GameElementTool::display()
{
    glPushMatrix();
    if(getCurrentType()==SWITCH && switchMode)
    {
        glColor3f(1,0,1);
        glLineWidth(20);
        glBegin(GL_LINES);
        glVertex3f(currentElement->geometry.center.x,currentElement->geometry.center.y,currentElement->geometry.center.z);
        glVertex3f(switchCursorPos.x,switchCursorPos.y,switchCursorPos.z);
        glEnd();


    }
    else
    {
        glDisable(GL_LIGHTING);
        Drawing::drawWireVoxel(elementCursorPos.x,
                               getCurrentType()==LADDER?elementCursorPos.y:elementCursorPos.y+1,
                               elementCursorPos.z);
        glEnable(GL_LIGHTING);
    }

    if(currentElement)
    {
        Drawing::drawWireCuboid(currentElement->geometry.start,currentElement->geometry.end,0,255,255,5);
        if(getCurrentType()==SWITCH)
        {
            ElementSwitch* s = getCurrentElement<ElementSwitch,SWITCH>();
            if(s->getTargets().size()>0)
            {
                int index = gameCtx->getSwitchCurrentTarget();
                GameElement* temp = s->getTargets()[index];
                Drawing::drawWireCuboid(temp->geometry.start,temp->geometry.end,255,255,0,5);
            }
        }
    }

    glPopMatrix();
}

Result GameElementTool::mouseReleaseEvent(QMouseEvent *event){
    return Result(true);
}
